/*
 * Player.cpp
 *
 *  Created on: 2 Nov 2012
 *      Author: guy
 */

#include "core/Player.h"
#include "core/Input.h"
#include "core/Time.h"
#include "types/Color.h"
#include "core/Screen.h"
#include "core/Resources.h"

#include <sstream>

using namespace SolidityEngine;

Player::Player():
    _scene(NULL),
    _running(false),
    _rendersurface(std::unique_ptr<SDL_Surface>()),
    _screenoffset(0,0)
{
    //initialise ttf handling if not already done so
    if(TTF_Init()==-1){
        throw "SDL_TTF failed to initialise";
    }

    //initialise audio
    if(Mix_OpenAudio(MIX_DEFAULT_FREQUENCY,MIX_DEFAULT_FORMAT,2,512)==-1){
       throw "SDL_mixer failed to initialise";
    }

    //initialise the screen
    if(Screen::RequestedResolution().FullScreen()){
       _rendersurface=std::unique_ptr<SDL_Surface>(SDL_SetVideoMode(Screen::RequestedResolution().Width(),Screen::RequestedResolution().Height(),32,SDL_FULLSCREEN|SDL_HWSURFACE|SDL_DOUBLEBUF));
    }
    else{
       _rendersurface=std::unique_ptr<SDL_Surface>(SDL_SetVideoMode(Screen::RequestedResolution().Width(),Screen::RequestedResolution().Height(),32,SDL_HWSURFACE|SDL_DOUBLEBUF));
    }

    //_rendersurface is now the render surface.. anything drawn on here will be rendered to the screen during the SDL_flip command
    if(!_rendersurface){
        throw "SDL_surface could not be created";
    }

    //initialise filesystem resources
    Resources::Initialize();

}

Player::~Player(){
    TTF_Quit();
}

int UpdateThread(void* ptr)
{

    bool _running = true;

    while(_running){

        //update static interfaces
        Time::Update();
        Input::Update();
        //check for quit event
        if(Input::Exit()){
            _running=false;
        };

        //update the scene
        Scene* scene = static_cast<Scene*>(ptr);
        if(scene) scene->Update();

    }

    return 0;
}

void Player::_Loop(){

    SDL_Thread* thread = SDL_CreateThread(UpdateThread, _scene);

    while(_running && thread){

        //update graphics
        if(_rendersurface==NULL){
            std::cerr<<"Trying to render frame before engine initialisation!"<<std::endl;
        }
        else{

            //clear the screen
            SDL_FillRect(_rendersurface.get(),NULL, Screen::ClearColor().GetPixelValue(_rendersurface.get()));

            if(_scene){

                std::shared_ptr<SDL_Surface> tempsurf = _scene->GetFrame();

                SDL_Rect subimage = tempsurf->clip_rect;



                //calculate limits that the viewport can go to
                int xhi = _scene->GetSize().X()-Screen::Width();
                int xlo = 0;
                int yhi = _scene->GetSize().Y()-Screen::Height();
                int ylo = 0;

                //stop the view from going over the scene size
                if(_screenoffset.X()>xhi){
                    subimage.x=xhi;
                }
                else if(_screenoffset.X()<xlo){
                    subimage.x=xlo;
                }
                else{
                    subimage.x=_screenoffset.X();
                }

                if(_screenoffset.Y()>yhi){
                    subimage.y=yhi;
                }
                else if(_screenoffset.Y()<ylo){
                    subimage.y=ylo;
                }
                else{
                    subimage.y=_screenoffset.Y();
                }

                //render onto the render surface
                SDL_BlitSurface(tempsurf.get(),&subimage,_rendersurface.get(),NULL);
                //no need to free surface, should be done in the shared_ptr deleter

                //render any screen-bound stuff
                _scene->RenderScreen(_rendersurface.get());

            }
            //swap buffers
            SDL_Flip(_rendersurface.get());
        }

    }

    SDL_FreeSurface(_rendersurface.release());
}

